package cn.sharp.bbs.service.impl;

import cn.sharp.bbs.dao.gen.*;
import cn.sharp.bbs.dao.score.BillDao;
import cn.sharp.bbs.dao.score.TaskDao;
import cn.sharp.bbs.entity.BO.TaskEntity;
import cn.sharp.bbs.entity.DO.Bill;
import cn.sharp.bbs.entity.DO.Datadict;
import cn.sharp.bbs.entity.DO.Task;
import cn.sharp.bbs.entity.DO.Taskrate;
import cn.sharp.bbs.event.*;
import cn.sharp.bbs.service.TaskService;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @className: TaskServiceImpl
 * @description: 积分任务相关服务实现类
 * @author: 王晓崧
 * @date: 2022/7/9
 **/
@Service
@Transactional
public class TaskServiceImpl implements TaskService {
    @Resource
    private TaskDao taskDao;

    @Resource
    private BillDao billDao;

    @Resource
    private TaskMapper taskMapper;

    @Resource
    private UserMapper userMapper;

    @Resource
    private TaskrateMapper taskrateMapper;

    @Resource
    private BillMapper billMapper;

    @Resource
    private CommentMapper commentMapper;

    @Resource
    private LikeMapper likeMapper;

    @Resource
    private CollectpostMapper collectpostMapper;


    @Resource
    private FollowpostMapper followpostMapper;

    @Resource
    private FollowuserMapper followuserMapper;

    /**
     * 创建任务实现
     *
     * @param taskEntity 任务实体
     * @param u_id       创建用户
     */
    @Override
    public void createTask(TaskEntity taskEntity, Long u_id) {
        System.out.println(taskEntity);
        Task task = new Task();
        task.setUserId(u_id);//设置任务创建者id
        task.setTime(new Date());//设置任务创建时间

        task.setName(taskEntity.getName());//设置任务名称
        task.setScore(taskEntity.getScore());//设置任务奖励分数
        task.setQuota(taskEntity.getQuota());//设置任务设置指标
        task.setStime(taskEntity.getStime());//设置任务开始时间
        task.setEtime(taskEntity.getEtime());//设置任务结束时间
        //获取当前类型对应编码并设置任务类型
        Datadict datadict = new Datadict();
        datadict.setType("task_type");
        datadict.setName(taskEntity.getType());
        task.setType(taskDao.getCodeByDict(datadict));
        setState(task);//设置当前任务状态
        //将任务插入任务列表
        taskMapper.insert(task);
    }

    /**
     * 设置当前任务状态
     *
     * @param task 任务
     */
    private void setState(Task task) {
        if (task.getStime() == null) {
            if (task.getEtime() == null) {
                task.setState(0);
            } else {
                if (task.getEtime().before(new Date())) {
                    task.setState(1);
                } else {
                    task.setState(0);
                }
            }
        } else {
            if (task.getEtime() == null) {
                if (task.getStime().after(new Date())) {
                    task.setState(-1);
                } else {
                    task.setState(0);
                }
            } else {
                if (task.getStime().after(new Date())) {
                    task.setState(-1);
                } else if (task.getEtime().before(new Date())) {
                    task.setState(1);
                } else {
                    task.setState(0);
                }
            }
        }
    }

    /**
     * 获取任务类型列表
     */
    @Override
    public List<String> getTaskTypeList() {
        List<Datadict> datadicts = taskDao.getTaskTypeList();
        List<String> taskTypeList = new ArrayList<>();
        for (Datadict datadict : datadicts) {
            taskTypeList.add(datadict.getName());
        }
        return taskTypeList;
    }

    /**
     * 获取任务列表
     */
    @Override
    public List<TaskEntity> getTaskList() {
        List<Task> taskList = taskMapper.selectAll();
        List<TaskEntity> taskEntities = new ArrayList<>();

        for (Task task : taskList) {
            TaskEntity taskEntity = new TaskEntity();
            taskEntity.setTaskID(task.getId());//设置任务id
            taskEntity.setCreateName(userMapper.selectByPrimaryKey(task.getUserId()).getName());//获取任务创建人名称
            taskEntity.setTime(task.getTime());//获取任务创建时间
            taskEntity.setName(task.getName());//获取任务名称
            taskEntity.setEtime(task.getEtime());//获取结束时间
            taskEntity.setStime(task.getStime());//获取任务开始时间
            taskEntity.setQuota(task.getQuota());//获取任务指标
            taskEntity.setScore(task.getScore());//获得奖励积分数额
            //获取任务类型
            Datadict datadict = new Datadict();
            datadict.setType("task_type");
            datadict.setCode(task.getType());
            taskEntity.setType(taskDao.getNameByDict(datadict));
            //将任务插入任务列表
            taskEntities.add(taskEntity);
        }
        return taskEntities;
    }

    /**
     * 获取任务完成进度列表
     *
     * @param u_id 用户id
     */
    @Override
    public List<TaskEntity> getRate(Long u_id) {
        List<Taskrate> taskList = taskDao.getSameDayTask(u_id);
        List<TaskEntity> taskEntities = new ArrayList<>();
        for (Taskrate taskrate : taskList) {
            TaskEntity taskEntity = new TaskEntity();
            Task task = taskMapper.selectByPrimaryKey(taskrate.getTaskId());

            taskEntity.setRate(taskrate.getRate());//获得进度
            taskEntity.setName(task.getName());//获取名称
            taskEntity.setQuota(task.getQuota());//获得指标
            taskEntity.setScore(task.getScore());//获得奖励积分数额

            taskEntities.add(taskEntity);
        }
        return taskEntities;
    }

    /**
     * 监听登录事件，
     * 用户登录时检查此次登录时间与上次登录是否为同一天，若不是同一天则在任务进度表中添加所有进行中任务与该用户对应项，并将进度置为0
     *
     * @param loginEvent 登录事件
     */
    @Override
    @EventListener
    public void LoginRate(LoginEvent loginEvent) {
        Long userID = loginEvent.getUserID();
//        Date lastTime = taskDao.getLastTime(userID);
//
//        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
//        if (lastTime == null || (!simpleDateFormat.format(lastTime).equals(simpleDateFormat.format(new Date())))) {//判断上次生成的任务进度是否和这次是同一天,判断lsatTime是否为空
//            List<Task> taskList = taskDao.getSameDayTaskList();
//            for (Task task : taskList) {
//                Taskrate taskrate = new Taskrate();
//                taskrate.setTaskId(task.getId());//设置任务id
//                taskrate.setRate(0);//设置进度为0
//                taskrate.setTime(new Date());//设置时间
//                taskrate.setUserId(userID);//设置任务进度人id
//                taskrateMapper.insert(taskrate);//插入任务进度表
//
//                setState(task);
//                taskMapper.updateByPrimaryKey(task);
//            }
//        }

        List<Task> taskList = taskDao.getSameDayTaskList();//拿到当前进行的任务列表
        List<Taskrate> taskrateList = taskDao.getSameDayTask(userID);//拿到当前用户当前时间的任务进度列表
        List<Long> taskIdList = taskList.stream().map(Task::getId).collect(Collectors.toList());//把实体里面的Id单独抽取出来
        List<Long> taskIdRateList = taskrateList.stream().map(Taskrate::getTaskId).collect(Collectors.toList());//把实体里面的taskId单独抽取出来
//        for (Long taskId : taskIdList) {
//            if (!taskIdRateList.contains(taskId)) {
//                Task task = taskMapper.selectByPrimaryKey(taskId);
//                Taskrate taskrate = new Taskrate();
//                taskrate.setTaskId(task.getId());//设置任务id
//                taskrate.setRate(0);//设置进度为0
//                taskrate.setTime(new Date());//设置时间
//                taskrate.setUserId(userID);//设置任务进度人id
//                taskrateMapper.insert(taskrate);//插入任务进度表
//            }
//        }
        taskIdList.stream().filter(taskId -> !taskIdRateList.contains(taskId)).forEach(
                taskId -> {
                    Task task = taskMapper.selectByPrimaryKey(taskId);
                    Taskrate taskrate = new Taskrate();
                    taskrate.setTaskId(task.getId());//设置任务id
                    taskrate.setRate(0);//设置进度为0
                    taskrate.setTime(new Date());//设置时间
                    taskrate.setUserId(userID);//设置任务进度人id
                    taskrateMapper.insert(taskrate);//插入任务进度表
                });
    }

    /**
     * 监听评论事件
     * 查询当前用户任务进度表，找到任务类型是“评论”的记录，将其进度属性+1
     * 若进度属性等于任务指标，则在积分收支记录表中增加一条记录，否则不做处理
     *
     * @param commentEvent 评论事件
     */
    @Override
    @EventListener
    public void commentRate(CommentEvent commentEvent) {
        Long userID = commentMapper.selectByPrimaryKey(commentEvent.getKey()).getUserId();
        taskRegistration(userID, "评论");
    }


    /**
     * 监听回复事件
     * 查询当前用户任务进度表，找到任务类型是“评论”的记录，将其进度属性+1
     * 若进度属性等于任务指标，则在积分收支记录表中增加一条记录，否则不做处理
     *
     * @param replyEvent 回复事件
     */
    @Override
    @EventListener
    public void replyRate(ReplyEvent replyEvent) {
        Long userID = commentMapper.selectByPrimaryKey(replyEvent.getKey()).getUserId();
        taskRegistration(userID, "评论");
    }

    /**
     * 监听评论点赞事件
     * 查询当前用户任务进度表，找到任务类型是“点赞”的记录，将其进度属性+1
     * 若进度属性等于任务指标，则在积分收支记录表中增加一条记录，否则不做处理
     *
     * @param commentLikeEvent 评论点赞事件
     */
    @Override
    @EventListener
    public void commentLikeRate(CommentLikeEvent commentLikeEvent) {
        Long userID = likeMapper.selectByPrimaryKey(commentLikeEvent.getKey()).getUserId();
        taskRegistration(userID, "点赞");
    }

    /**
     * 监听帖子点赞事件
     * 查询当前用户任务进度表，找到任务类型是“点赞”的记录，将其进度属性+1
     * 若进度属性等于任务指标，则在积分收支记录表中增加一条记录，否则不做处理
     *
     * @param postLikeEvent 帖子点赞事件
     */
    @Override
    @EventListener
    public void postLikeRate(PostLikeEvent postLikeEvent) {
        Long userID = likeMapper.selectByPrimaryKey(postLikeEvent.getKey()).getUserId();
        taskRegistration(userID, "点赞");
    }

    /**
     * 监听收藏事件
     * 查询当前用户任务进度表，找到任务类型是“收藏帖子”的记录，将其进度属性+1
     * 若进度属性等于任务指标，则在积分收支记录表中增加一条记录，否则不做处理
     *
     * @param collectEvent 收藏事件
     */
    @Override
    @EventListener
    public void collectRate(CollectEvent collectEvent) {
        Long userID = collectpostMapper.selectByPrimaryKey(collectEvent.getKey()).getUserId();
        taskRegistration(userID, "收藏帖子");
    }

    /**
     * 监听关注用户事件
     * 查询当前用户任务进度表，找到任务类型是“关注用户”的记录，将其进度属性+1
     * 若进度属性等于任务指标，则在积分收支记录表中增加一条记录，否则不做处理
     *
     * @param followEvent 关注用户事件
     */
    @Override
    @EventListener
    public void followRate(FollowEvent followEvent) {
        Long userID = followuserMapper.selectByPrimaryKey(followEvent.getKey()).getUserId();
        taskRegistration(userID, "关注用户");
    }

    /**
     * 监听关注帖子事件
     * 查询当前用户任务进度表，找到任务类型是“关注帖子”的记录，将其进度属性+1
     * 若进度属性等于任务指标，则在积分收支记录表中增加一条记录，否则不做处理
     *
     * @param postFollow 关注帖子事件
     */
    @Override
    @EventListener
    public void postFollowRate(PostFollow postFollow) {
        Long userID = followpostMapper.selectByPrimaryKey(postFollow.getKey()).getUserId();
        taskRegistration(userID, "关注帖子");
    }

    /**
     * 监听浏览帖子事件
     * 查询当前用户任务进度表，找到任务类型是“浏览帖子”的记录，将其进度属性+1
     * 若进度属性等于任务指标，则在积分收支记录表中增加一条记录，否则不做处理
     *
     * @param browseEvent 浏览帖子事件
     */
    @Override
    @EventListener
    public void browseRat(BrowseEvent browseEvent) {
        Long userID = browseEvent.getKey();
        taskRegistration(userID, "浏览帖子");
    }

    /**
     * 监听发帖事件
     * 查询当前用户任务进度表，找到任务类型是“发帖”的记录，将其进度属性+1
     * 若进度属性等于任务指标，则在积分收支记录表中增加一条记录，否则不做处理
     *
     * @param postCreateEvent 发帖事件
     */
    @Override
    @EventListener
    public void postCreateRate(PostCreateEvent postCreateEvent) {
        Long userID = postCreateEvent.getKey();
        taskRegistration(userID, "发帖");
    }

    /**
     * 用户签到
     * 查询当前用户任务进度表，找到任务类型是“签到”的记录，将其进度属性+1
     * 在积分收支记录表中增加一条记录
     *
     * @param u_id 用户id
     */
    @Override
    public void signIn(Long u_id) {
        taskRegistration(u_id, "签到");
    }

    /**
     * 检查请求发起者是否是管理员
     *
     * @param u_id 用户id
     * @return true 代表是管理员，false 代表不是管理员
     */
    @Override
    public boolean checkIsAdministrator(Long u_id) {
        return taskDao.checkIsAdministrator(u_id) != 0;
    }

    /**
     * 检查用户今日是否已经签到
     *
     * @param u_id 用户id
     * @return true 代表已签到 false 代表未签到
     */
    @Override
    public boolean checkIsSignIn(Long u_id) {
        System.out.println(taskDao.checkIsSignIn(u_id));
        return taskDao.checkIsSignIn(u_id) != 0;
    }


    /**
     * 任务登记函数
     * 根据用户id和操作进行对应类型任务进度更新，并在积分收支记录表中操作
     * 查询当前用户任务进度表，找到任务类型是“”的记录，将其进度属性+1
     * 若进度属性等于任务指标，则在积分收支记录表中增加一条记录，否则不做处理
     *
     * @param u_id         用户id
     * @param taskTypeName 操作
     */
    private void taskRegistration(Long u_id, String taskTypeName) {
        List<Task> taskList = taskDao.getSameDayTaskList();//查询当天所有任务

        //新建数据字典类，设置name为“发帖”,类型为"task_type"
        Datadict datadict = new Datadict();
        datadict.setType("task_type");
        datadict.setName(taskTypeName);
        int taskCode = taskDao.getCodeByDict(datadict);

        for (Task task : taskList) {//对所有查询到的任务循环
            if (task.getType() == taskCode) {//如果其中有任务类型与 taskTypeName 相同的
                //新建任务进度类，并设置任务id和用户id
                Taskrate rate = new Taskrate();
                rate.setTaskId(task.getId());
                rate.setUserId(u_id);
                Taskrate taskrate = taskDao.getTaskRate(rate);//通过rate查询当日对应任务进度

                Integer temp = taskrate.getRate() + 1;//进度+1
                taskrate.setRate(temp);//设置进度

                if (task.getQuota() > temp) {//进度小于任务指标
                    taskrateMapper.updateByPrimaryKey(taskrate);//更新任务进度
                } else if (Objects.equals(task.getQuota(), temp)) {//进度等于任务指标
                    taskrateMapper.updateByPrimaryKey(taskrate);//更新任务进度

                    Bill bill = new Bill();//新建账单类
                    bill.setUserGet(taskrate.getUserId());//设置积分接收人id
                    bill.setNum(task.getScore());//设置积分数额
                    bill.setFrom(task.getId());//设置来源id
                    //设置来源类型
                    Datadict datadictTemp = new Datadict();
                    datadictTemp.setType("bill_type");
                    datadictTemp.setName("任务");
                    int billCode = billDao.getCodeByDict(datadictTemp);
                    bill.setType(billCode);
                    bill.setTime(new Date());//设置账单建立时间
                    billMapper.insert(bill);//插入数据库

                }
            }
        }
    }
}
